package hollycrm.com.libuip.utils;

import android.support.v4.util.ArrayMap;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.Map;

import hollycrm.com.libuip.socket.UIPMessage;

/**
 * Created by aber on 2017/1/17.
 * converter for UIPMessage
 */

public class UIPMessageAdapter extends TypeAdapter<UIPMessage> {

    private static final String ID = "MessageID";

    private static final String TYPE = "MessageType";

    private static final String Status = "MessageStatus";

    private static final String Primary = "PrivateData";

    @Override
    public void write(JsonWriter out, UIPMessage value) throws IOException {
        if (value == null)
            return;
        out.beginObject();
        out.name(ID).value(value.id)
                .name(TYPE).value(value.type);
        out.name(Status).value(value.status);
        Map<String,Object> body = value.body;
        if (!body.isEmpty()) {
            for (String item: body.keySet()) {
                Object mapValue = body.get(item);
                out.name(item);
                if (mapValue instanceof Integer) {
                    out.value((int)mapValue);
                }else if (mapValue instanceof Boolean) {
                    out.value((boolean) mapValue);
                }else if (mapValue instanceof String) {
                    out.value((String)mapValue);
                }else if (mapValue instanceof Number) {
                    out.value((Number)mapValue);
                }else if (mapValue == null){
                    out.nullValue();
                }
            }
        }
        if (value.data != null && !value.data.isEmpty()) {
            out.name(Primary);
            writePrimaryData(value.data, out);
        }
        out.endObject();
    }

    @Override
    public UIPMessage read(JsonReader in) throws IOException {
        in.beginObject();
        UIPMessage.Builder builder = UIPMessage.newBuilder();
        while (in.hasNext()) {
            String name = in.nextName();
            if (name.equals(ID)) {
                builder.setId(in.nextString());
            }else if (name.equals(TYPE)){
                builder.setType(in.nextString());
            }else if (name.equals(Status)) {
                builder.setStatus(in.nextInt());
            }else if (name.equals(Primary)) {
                builder.setBundleData(getPrimaryData(in));
            }else {
                switch (in.peek()) {
                    case NUMBER:
                        builder.setIntBody(name,in.nextInt());
                        break;
                    case STRING:
                        builder.setStringBody(name,in.nextString());
                        break;
                    case BOOLEAN:
                        builder.setBoolBody(name,in.nextBoolean());
                        break;
                    default:
                        in.skipValue();
                        break;
                }
            }
        }
        in.endObject();
        return builder.build();
    }

    private void writePrimaryData(Map<String,Object> data, JsonWriter out) throws IOException {
        out.beginObject();
        if (!data.isEmpty()) {
            for (String item: data.keySet()) {
                Object mapValue = data.get(item);
                out.name(item);
                if (mapValue instanceof Integer) {
                    out.value((int)mapValue);
                }else if (mapValue instanceof Boolean) {
                    out.value((boolean) mapValue);
                }else if (mapValue instanceof String) {
                    out.value((String)mapValue);
                }else if (mapValue instanceof Number) {
                    out.value((Number)mapValue);
                }else if (mapValue == null){
                    out.nullValue();
                }
            }
        }
        out.endObject();
    }

    private Map<String,Object> getPrimaryData(JsonReader in) throws IOException{
        Map<String,Object> args = new ArrayMap<>();
        in.beginObject();
        while (in.hasNext()) {
            String name = in.nextName();
            switch (in.peek()) {
                case NUMBER:
                    args.put(name,in.nextDouble());
                    break;
                case STRING:
                    args.put(name,in.nextString());
                    break;
                case BOOLEAN:
                    args.put(name,in.nextBoolean());
                    break;
                default:
                    in.skipValue();
                    break;
            }
        }
        in.endObject();
        return args;
    }
}
